/*
 * DIM-SUM操作系统 - 架构相关的启动过程
 *
 * Copyright (C) 2023 国科础石(重庆)软件有限公司
 *
 * 作者: Dong Peng <w-pengdong@kernelsoft.com>
 *
 * License terms: GNU General Public License (GPL) version 3
 *
 */

#include <dim-sum/board_config.h>
#include <dim-sum/boot_allotter.h>
#include <dim-sum/init.h>
#include <dim-sum/irq.h>
#include <dim-sum/percpu.h>
#include <dim-sum/smp_lock.h>
#include <dim-sum/devtree.h>
#include <clocksource/arm_arch_timer.h>
#include <asm/cputype.h>
#include <asm/early_map.h>
#include <asm/irqflags.h>
#include <asm/memory.h>
#include <asm/processor.h>
#include <asm/tlbflush.h>
#include <asm/mmu_context.h>

void __init init_riscv_stvec(void);

extern void* handle_exception[];
void __init init_IRQ(void)
{
	arch_init_irq();
}

void __init init_time(void)
{
	init_time_arch();
}

void __init init_riscv_stvec(void)
{
	csr_write(sscratch, 0);
	/* 设置异常向量地址 */
	csr_write(stvec, &handle_exception);
	/* 开启所有中断 */
	csr_set(CSR_IE, IE_TIE);
	csr_set(CSR_IE, IE_EIE);
	csr_set(CSR_IE, IE_SIE);

}

void __init start_arch(void)
{
	/**
	 * 先设置CPU，避免CPU BUG引起故障
	 */
	smp_setup_processor_id(); 
	init_arch_cpu();
	parse_device_configs();
	boot_state = EARLY_INIT;
	/**
	 * 设置boot内存区间
	 * 终于可以分配内存了:)
	 */

	init_boot_mem_area(boot_memory_start, boot_memory_end);

	init_allmemmap_kernel_tbl();

	/**
	 * 固定映射初始化
	 * 在init_mm中创建页表目录项
	 */
	init_early_map_early();

	
	/**
	 * 设备树初始化
	 * 从uboot 传入的fdt_addr中解析得到设备树节点信息
	 */

	dt_init();

	/**
	 * 为pl011创建简单控制台
	 * 需要进行固定映射，因此放在init_fixmap_early之后
	 */

	init_simple_console("riscv,sbi");
	init_sbi();

	init_sched_early();

	/**
	 * 创建简单控制台后，可以用打印函数进行调试了
	 * Sounds Good:)
	 */

	/**
	 * 此时已经注册了简单控制台
	 * 可以打开async异常
	 * 在异常时可以打印调试
	 */
	enable_async();
	/**
	 * 为per-cpu分配每个CPU上的内存
	 * 并记下每个CPU上的偏移量
	 */
	init_per_cpu_offsets();
	/**
	 * 每个CPU启动时，都应当调用
	 * percpu变量需要
	 */
	set_this_cpu_offset(per_cpu_offset(smp_processor_id()));
	init_riscv_stvec();
	// BUG_ON(load_elf((void*)linear_phys_to_virt(0X60000000)));
}

asmlinkage __init void slave_start_arch(struct slave_cpu_data *slave_cpu_data)
{
	int cpu;
	cpu = slave_cpu_data->cpu;

	smp_processor_id() = cpu;
	set_sapt(kernel_tbl_page);
	local_flush_tlb_all();
	
	set_tp_reg((unsigned long)current_proc_info());

	set_this_cpu_offset(per_cpu_offset(smp_processor_id()));

	mark_cpu_online(cpu, true);
	init_riscv_stvec();
}